package com.net.xpay.clean.scheduler;


import com.net.common.annotation.WriteTransactional;
import com.net.common.dao.OrderCondition;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.stat.UserAccountMoneyLeftStat;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.manager.stat.UserAccountMoneyLeftStatManager;
import com.net.xpay.common.model.search.UserSearchModel;
import com.net.xpay.core.domain.AccountLog;
import com.net.xpay.core.domain.UserAccount;
import com.net.xpay.core.enums.AccountFundType;
import com.net.xpay.core.manager.AccountLogManager;
import com.net.xpay.core.manager.UserAccountManager;
import com.net.xpay.core.model.AccountLogSearchModel;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 临时用一下的 用完就删除掉逻辑
 */
@Slf4j
//@Component
public class TmpScheduler {

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private UserAccountManager userAccountManager;

    @Autowired
    private AccountLogManager accountLogManager;

    @Autowired
    private UserAccountMoneyLeftStatManager userAccountMoneyLeftStatManager;

    @Scheduled(cron = "0 59 18 * * ?")
    public void tmp1() {
        log.info("tmp1 start");
        //把3月3号之前的数据倒推回去
        LocalDate day = LocalDate.now().minusDays(1L);
        List<UserAccountMoneyLeftStat> userAccountMoneyLeftStats = userAccountMoneyLeftStatManager.listByDay(day);

        for (UserAccountMoneyLeftStat stat : userAccountMoneyLeftStats) {
            User user = userManager.getById(stat.getUserId());
            UserShard userShard = userShardManager.getById(user.getId());
            try {
                ShardUtil.setShardContext(userShard.getShardId());
                stat(user, stat, day);
            } finally {
                ShardUtil.cleanShardContext();
            }

            log.info("stat tmp1 finished userId={}", stat.getUserId());
        }
        log.info("tmp2 start");
    }

    private void stat(User user, UserAccountMoneyLeftStat stat, LocalDate day) {
        //先把3月3号的数据修正掉
        AccountLogSearchModel searchModel1 = new AccountLogSearchModel();
        searchModel1.setUserId(stat.getUserId());
        searchModel1.setAccountFundType(AccountFundType.MONEY);
        searchModel1.setCreateMinTime(LocalDateUtil.getDayStart(day));
        searchModel1.setCreateMaxTime(LocalDateUtil.getDayStart(day.plusDays(1L)));
        long change1 = accountLogManager.sumAccountLog(searchModel1);
        stat.setChangeMoney(change1);
        stat.setBeforeMoneyLeft(stat.getMoneyLeft() - change1);
        userAccountMoneyLeftStatManager.update(stat);

        LocalDate nextDay = day.minusDays(1L);

        LocalDate endDay = LocalDate.of(2023, 12, 31);


        //用户在这天还没注册直接结束
        List<UserAccountMoneyLeftStat> stats = new ArrayList<>();
        while (true) {
            if (user.getRegisterTime().toLocalDate().isAfter(nextDay)) {
                break;
            }
            if (nextDay.isBefore(endDay)) {
                break;
            }
            UserAccountMoneyLeftStat next = new UserAccountMoneyLeftStat();
            //查询该用户当天的账户变动值 0点到23点59分59秒
            AccountLogSearchModel searchModel = new AccountLogSearchModel();
            searchModel.setUserId(stat.getUserId());
            searchModel.setAccountFundType(AccountFundType.MONEY);
            searchModel.setCreateMinTime(LocalDateUtil.getDayStart(nextDay));
            searchModel.setCreateMaxTime(LocalDateUtil.getDayStart(nextDay.plusDays(1L)));
            long change = accountLogManager.sumAccountLog(searchModel);
            next.setUserId(user.getId());
            next.setDay(nextDay);
            next.setChangeMoney(change);
            next.setMoneyLeft(stat.getBeforeMoneyLeft());
            next.setBeforeMoneyLeft(next.getMoneyLeft() - change);
            stats.add(next);

            stat = next;

            nextDay = nextDay.minusDays(1L);
        }

        int length = stats.size();
        for (int i = length - 1; i >= 0; i--) {
            UserAccountMoneyLeftStat prev = stats.get(i);
            userAccountMoneyLeftStatManager.save(prev);
        }
    }


    //    @Scheduled(cron = "0 18 2 * * ?")
    public void tmp() {
        log.info("tmp start");
        LocalDate day = LocalDate.now().minusDays(1L);
        //最近20天
        LocalDateTime startTime = LocalDateUtil.getDayStart(LocalDate.now().minusDays(20L));
        LocalDateTime endTime = LocalDateUtil.getDayStart(LocalDate.now());
        List<Long> ids = userManager.listIds(new UserSearchModel());
        for (Long id : ids) {
            try {
                AccountLog targetLog;
                UserShard userShard = userShardManager.getById(id);
                ShardUtil.setShardContext(userShard.getShardId());

                AccountLogSearchModel searchModel = new AccountLogSearchModel();
                searchModel.setUserId(id);
                searchModel.setCreateMinTime(startTime);
                searchModel.setCreateMaxTime(endTime);
                searchModel.setColumn("create_time");
                searchModel.setOrderby(OrderCondition.ORDER_BY_DESC);
                List<AccountLog> accountLogs = accountLogManager.search(searchModel);
                if (CollectionUtils.isEmpty(accountLogs)) {
                    //昨天没有资金变动
                    calNoChangeAccount(id);
                    continue;
                }

                if (accountLogs.size() == 1 || id == 10761L || id == 10806L) {
                    targetLog = accountLogs.get(0);
                } else {
                    //第一条和最后一条时间相等 说明排序无效
                    if (accountLogs.get(0).getCreateTime().equals(accountLogs.get(accountLogs.size() - 1).getCreateTime())) {
                        log.warn("check error1 accountLogs={}", SerializationUtil.obj2String(accountLogs));
                    }

                    //有记录 核查一下排序
                    AccountLog before = accountLogs.get(0);
                    for (int i = 1; i < accountLogs.size(); i++) {
                        AccountLog next = accountLogs.get(i);
                        if (!before.getBeforeAmount().equals(next.getAfterAmount())) {
                            log.info("check error2 accountLogs={}", SerializationUtil.obj2String(accountLogs));
                            throw new RuntimeException("异常中断");
                        }
                        before = next;
                    }
                    targetLog = accountLogs.get(0);
                }

                UserAccountMoneyLeftStat stat = new UserAccountMoneyLeftStat();
                stat.setDay(day);
                stat.setUserId(id);
                stat.setMoneyLeft(targetLog.getAfterAmount());
                userAccountMoneyLeftStatManager.save(stat);

            } finally {
                ShardUtil.cleanShardContext();
            }
        }


        log.info("tmp end");
    }


    @WriteTransactional
    public void calNoChangeAccount(Long id) {
        UserAccount userAccount = userAccountManager.getByIdWithLock(id);
        //查下今天有没有变化
        log.info("calNoChangeAccount start id={}", id);
        LocalDate day = LocalDate.now();
        LocalDateTime startTime = LocalDateUtil.getDayStart(day);
        LocalDateTime endTime = LocalDateUtil.getDayStart(day.plusDays(1L));
        AccountLogSearchModel accountLogSearchModel = new AccountLogSearchModel();
        accountLogSearchModel.setUserId(id);
        accountLogSearchModel.setCreateMinTime(startTime);
        accountLogSearchModel.setCreateMaxTime(endTime);
        accountLogSearchModel.setColumn("create_time");
        accountLogSearchModel.setOrderby(OrderCondition.ORDER_BY_ASC);
        List<AccountLog> logs = accountLogManager.search(accountLogSearchModel);
        if (logs.size() > 0L) {
            //基本不可能
            log.info("calNoChangeAccount error|logs={}|id={}", SerializationUtil.obj2String(logs), id);
            UserAccountMoneyLeftStat stat = new UserAccountMoneyLeftStat();
            stat.setDay(day);
            stat.setUserId(id);
            stat.setMoneyLeft(logs.get(0).getBeforeAmount());
            userAccountMoneyLeftStatManager.save(stat);
            return;
        }


        UserAccountMoneyLeftStat stat = new UserAccountMoneyLeftStat();
        stat.setDay(day);
        stat.setUserId(id);
        stat.setMoneyLeft(userAccount.getMoneyLeft());
        userAccountMoneyLeftStatManager.save(stat);


    }


}
